<?php
/*
	Работа с пользователями в системе mvc.
	
	Создан: 2011-09-06
	author djerom
	version 0.0.0.1
*/
class c_mvc_user_model
{
	static $loaded_usernames = array();
	var $name = 'default';
	var $password = '';
    var $config = array();
	var $inerited_users = array();
	var $permissions = array();

	function c_mvc_user_model($name = 0)
	{
		global $mvc;
		$mvc->fill_class_vars($this);
		if ($name) $this->name = $name;
		elseif ($_SESSION['username']) $this->name = $_SESSION['username'];

		

		// Пользователь существует - загружаем.
		if ($this->exists())
		{
			$this->load($this->name);
			c_mvc_user_model::$loaded_usernames[$this->name] = true;
		}

		if (!isset($this->config['inherits'])) $this->config['inherits'] = array();
		
		// Загрузка наследуемых пользователей.
		foreach($this->config['inherits'] as $user)
		{
			// Если пользователя никогда не загружали, то подгрузим его. Защита от зацикливания.
			if (!isset(c_mvc_user_model::$loaded_usernames[$user]))
			{
				c_mvc_user_model::$loaded_usernames[$user] = true;
				$this->inerited_users[] = new c_mvc_user_model($user);
			}
		}
	}
	
	// Проверяет существует ли пользователь (по наличию его папки).
	function exists()
	{
		return file_exists($this->data_path());
	}
	
	// Войти в систему (Прописать в сессию данного пользователя как активного).
	function login($password)
	{
		global $mvc;
		
		if ( $this->exists() && ($this->password == md5($password)) )
		{		
			$_SESSION['username'] = $this->name;
			$mvc->user = $this;
			return true;
		}
		return false;
	}
	
	// Вошел ли пользователь под своим именем (Приписан в сессии).
	function logged()
	{
		return isset($_SESSION['username']);
	}
	
	// Выйти из системы (Удалить данного пользователя из сессии).
	function logout()
	{
		unset($_SESSION['username']);
		$this->load('default');
	}
	
	// Проверяет ссылку на разрешенность.
	function check_action($mask, $aparts, $aparams)
	{
		$mparts = parse_url($mask); // Разбираем запрос на путь и параметры.
		parse_str($mparts['query'], $mparams); // Разбираем параметры.
		$mparts = explode('/', $mparts['path']); // Делим путь на куски.
		
		// Если разрешение детальнее запроса, то оно не подходит.
		if (sizeof($mparts) <= sizeof($aparts))
		{			
			$result = true;
			for($i = 0; $i < sizeof($mparts); $i++)
			{					
				if (($mparts[$i] != '*') && ($aparts[$i] != $mparts[$i]))
				{
					$result = false;
					break;
				}
			}
			
			// Адрес найден. Сверяем параметры.
			$result &= ( sizeof($mparams) == sizeof(array_intersect($mparams, $aparams)) );
		}
		return $result;
	}
	
	// Проверка позволено ли данному пользователю переходить по данной ссылке с данными параметрами (служебная).
	// Возвращает 0 - найдено запрещение, 1 - найдено разрешение, 2 - ничего не найдено.
	function check_allowed($action, $params)
	{
		// Здесь проверяется разрешен ли данный url для перехода.
		// Сначала проверяется есть ли запрет на адрес. Если запрета нет, то ищется разрешение на адрес.
		// Если и запрета не найдено, то проверка производится в наследуемых пользователях в случайном порядке.
		// Если нигде данного адреса не найдено, то вернется статус 2. При разрешении 1, при запрете 0.
		// Каждая команда списка имеет формат url?params->(redirect_url), поэтому команду режем по символу ->,
		// Затем по ?, а затем по /.

		$aparts = explode('/', $action); // Режем адрес на сегменты.
		$default = '';
		
		//print_r($action);
		//die();
		$mode = 0; // Изначально запертить все.
		
		// 1. Ищем action в запрещенных командах.
		foreach($this->permissions as $permission)
		{
			if ($permission)
			{
				// Это директива #allow, #deny, #default.
				if ($permission == '#allow')
				{
					$mode = 1; // Дальше идет список разрешенных url.
				}
				elseif ($permission == '#deny')
				{
					$mode = 0; // Дальше идет список запещенных url.
				}
				elseif (substr($permission, 0, strlen('#default')) == '#default')
				{
					$default = trim(substr($permission, strlen('#default')));
				}
				else
				{		
					// Режем команду по симовлу переадресации -> и получим (url_want, [url_get]).
					$ref_parts = explode('->', $permission);
					
					$status = $this->check_action($ref_parts[0], &$aparts, &$params);
					// Нашли запрет или разрешение возвращаем статус и выходим.
					if ($status)
					{
						return array($mode, isset($ref_parts[1]) ? $ref_parts[1] : '');
					}
				}
			}
		}
		
		// Ничего не найдено проверяем умолчание.
		if ($default == '#deny') {
			return array(0, '');
		}
		elseif ($default == '#allow') {
			return array(1, '');
		}
		//elseif ($default) {
		//	return array(1, $default);
		//}
		else {
			return array(2, $default);
		}
	}	
	
	// Разрешен ли переход на страницу [true\false].
	function url_allowed($action)
	{
		$parts = parse_url($action);
		parse_str($parts['query'], $params);		
		$allowed = $this->allowed($parts['path'], $params);
		return ($allowed[0] == 1);
	}
	
	// Проверка позволено ли данному пользователю переходить по данной ссылке с данными параметрами.
	function allowed($action, $params)
	{
		$allowed = $this->check_allowed($action, $params);

		// Найдено разрешение\запрещение, вернем результат.
		if ($allowed[0] != 2) return $allowed;
		
		// Ничего не найдено, ищем в наследуемых пользователях.
		foreach($this->inerited_users as $user)
		{
			$allowed = $user->allowed($action, $params);
			// Найдено разрешение\запрещение, вернем результат.
			if ($allowed[0] != 2) return $allowed;
		}
	
		// Ничего не найдено, вернем статус 2.
		return $allowed;
	}
	
	// Путь к папке пользователя.
	function data_path()
	{
		global $mvc;
		return $this->data_path.'users/'.$this->name.'/';// mvc->parse('{base_path}users/'.$this->name.'/');
	}

	// Загрузить конфиг пользователя. $attach - объединить его с основным конфигом.
	function load($attach = false)
	{
		global $mvc;
		
		$this->config = $mvc->load_array($this->data_path().'conf.php');
		if(!$this->config) $this->config = array();
		
		//$this->allowed_actions = $mvc->load_array($this->data_path().'allow.php');
		//if(!$this->allowed_actions) $this->allowed_actions = array();

		//$this->disallowed_actions = $mvc->load_array($this->data_path().'disallow.php');
		//if(!$this->disallowed_actions) $this->disallowed_actions = array();
		
		$this->permissions = $mvc->load_array($this->data_path().'permissions.php');
		if(!$this->permissions) $this->permissions = array();
		
		$this->password = $this->config['password'];
		
		if ($attach)
		{
			$mvc->config = array_merge($mvc->config, $this->config);
			$mvc->db->connect();
		}
	}
	
	// Сохранить кониг пользователя в его папку.
	function save()
	{
		global $mvc;
		$datapath = $this->data_path();
		if (!file_exists($datapath))
		{
			mkdir($datapath, 0777, true);
			chmod($datapath, 0777);
		}
		
		// Менть пароль, только если он введен.
		if ($this->password)
			$this->config['password'] = $this->password;

		$mvc->save_array($this->config, $datapath.'conf.php');
		//$mvc->save_array($this->allowed_actions, $datapath.'allow.php');
		//$mvc->save_array($this->disallowed_actions, $datapath.'disallow.php');
		$mvc->save_array($this->permissions, $datapath.'permissions.php');
	}
	
	// Физически удалить все данные пользователя.
	function kill()
	{
		if ($this->exists())
			rrmdir($this->data_path());
	}
	
	// Получить список всех пользователей или ролей (начинается с _).
	function get_list($mode = 'all') // user | role | all
	{
		$data = glob($this->data_path."users/*");
		$res = array();
		foreach($data as $path)
		{
			$filename = basename($path);
			if ( ($mode == 'all') || ((substr($filename, 0, 1) == '_') && ($mode == 'role')) || ((substr($filename, 0, 1) != '_') && ($mode == 'user')) )// Это роль и запросили роли.
			{
				$res[] = $filename;
			}
		}
		return $res;
	}
}
?>